/**
 * promise的状态
 */
const PADDING = 'padding' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
class Mypromise {
    constructor(executor) {
        // 捕获执行器的错误
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.resolve(e)
        }
    }

    // promise的状态
    status = PADDING
    // 成功的值
    value = undefined
    // 失败的原因
    reason = undefined
    // 成功的回调
    resolveCallBack = []
    // 失败的回调
    rejectCallBack = []
    /**
     * 成功的回调函数
     */
    resolve = (value) => {
        // 判断状态如果是等待则修改状态，一个promise只能修改一次
        if (this.status !== PADDING) {
            return
        }
        this.status = FULFILLED
        this.value = value
        // 异步状态下无法使用then方法中进行回调函数的执行，所以将回调函数放到resolve和reject中
        while (this.resolveCallBack.length) {
            let resolveCallBack = this.resolveCallBack.shift()
            // 保证了变量是方法
            if (typeof resolveCallBack === 'function') {
                resolveCallBack(this.value)
            }
        }
    }
    /**
     * 失败的回调函数
     */
    reject = (reason) => {
        // 判断状态如果是等待则修改状态，一个promise只能修改一次
        if (this.status !== PADDING) {
            return
        }

        this.status = REJECTED
        this.reason = reason
        // 异步状态下无法使用then方法中进行回调函数的执行，所以将回调函数放到resolve和reject中
        while (this.rejectCallBack.length) {
            let rejectCallBack = this.rejectCallBack.shift()
            // 保证了变量是方法
            if (typeof rejectCallBack === 'function') {
                rejectCallBack(this.reason)
            }

        }
        // this.rejectCallBack && this.rejectCallBack(this.value)
    }
    /**
     * promise 执行结果的方法
     * @param {Function} resolve  成功回调 
     * @param {Function} reject   失败回调
     */
    then(resolveCallBack, rejectCallBack) {
        resolveCallBack = resolveCallBack?resolveCallBack:(value)=>value
        rejectCallBack = rejectCallBack?rejectCallBack:(err)=>err
        // 保证then后还能使用.then 来继续调用，所以必须返回一个promsie对象
        let promise = new Mypromise((resolve, reject) => {

            // 如果成功调用成功的回调函数
            if (this.status === FULFILLED) {
                // 为了能够拿到promise变量，将代码变成异步代码
                setTimeout(() => {
                    // 捕获成功回调的异常
                    try {
                        // 保证了变量是方法
                        if (typeof resolveCallBack === 'function') {
                            // 获取then的回调函数的返回值，给下一个then
                            let res = resolveCallBack(this.value)
                            resolcePromise(promise, res, resolve, reject)
                        }
                    } catch (error) {
                        reject(error)
                    }
                }, 0)


                // 如果失败调用失败的回调函数
            } else if (this.status === REJECTED) {
                // 为了能够拿到promise变量，将代码变成异步代码
                setTimeout(() => {
                    // 捕获失败回调的异常
                    try {
                        // 保证了变量是方法
                        if (typeof rejectCallBack === 'function') {
                            // 获取then的回调函数的返回值，给下一个then
                            let err = rejectCallBack(this.reason)
                            resolcePromise(promise, err, resolve, reject)
                            // resolcePromise(err,resolve,reject)
                        }
                    } catch (error) {
                        reject(error)
                    }
                }, 0)



                // 说明promise中执行了异步代码，将回调函数绑定到类上，
                // 异步执行到resolve和reject时再讲回调函数进行调用
            } else {
                this.resolveCallBack.push(() => {
                    // 为了能够拿到promise变量，将代码变成异步代码
                    setTimeout(() => {
                        // 捕获成功回调的异常
                        try {
                            // 保证了变量是方法
                            if (typeof resolveCallBack === 'function') {
                                // 获取then的回调函数的返回值，给下一个then
                                let res = resolveCallBack(this.value)
                                resolcePromise(promise, res, resolve, reject)
                            }
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.rejectCallBack.push(() => {
                    // 为了能够拿到promise变量，将代码变成异步代码
                    setTimeout(() => {
                        // 捕获失败回调的异常
                        try {
                            // 保证了变量是方法
                            if (typeof rejectCallBack === 'function') {
                                // 获取then的回调函数的返回值，给下一个then
                                let err = rejectCallBack(this.reason)
                                resolcePromise(promise, err, resolve, reject)
                                // resolcePromise(err,resolve,reject)
                            }
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })
        return promise
    }
    // pormise 最终的方法
    finally(callback){
        return this.then(value=>{
            return Mypromise.resolve(callback()).then(()=>value)
        },err=>{
            return Mypromise.reject(callback()).then(()=>{throw err})
        })
    }
    // promise 异常捕捉
    catch(rejectCallBack){
        return this.then(undefined,rejectCallBack)
    }

    // 静态的成功方法
    static resolve(value){
        if(value instanceof Mypromise){
            return value
        }else{
            return new Mypromise((resolve)=>[
                resolve(value)
            ])
        }
    }
    // 静态的失败方法
    static reject(value){
        if(value instanceof Mypromise){
            return value
        }else{
            return new Mypromise((resolve,reject)=>[
                reject(value)
            ])
        }
    }
    // 执行数组的promise方法
    static all(array){
        let len = array.length
        let restuls = new Array(len)
        return new Mypromise((resolve,reject)=>{
            function addData(index,res){
                restuls[index] = res
                // 如果 index的索引和 传入的数组长度一致，说明都一静执行完毕，可以往下执行then方法
                if(index === len-1){
                    resolve(restuls)
                }
            }
            // 循环传入的数据。如果是promise则使用then 保存值，否则按照普通值来保存
            for (let index = 0; index < array.length; index++) {
                let el = array[index];
                if(el instanceof Mypromise){
                    el.then(value=>{
                        addData(index,value)
                    },err=>reject(err))
                }else{
                    addData(index,el)
                }
                
            }
        })
        
    }
}


function resolcePromise(promise, res, resolve, reject) {
    // 判断新的promise是否和then 方法返回的是否是同一个，如果是则报错
    if (promise == res) {
        reject(new Error("promise 循环调用"))
        return
    }
    // 判断是否是pormise对象 是则使用resolve 和reject返回promise的值
    if (res instanceof Mypromise) {
        res.then(resolve, reject)
    } else {
        // 不是promise 直接返回值
        resolve(res)
    }
}